#include "mqtt_client.h"
#include <webclient.h>
#include <cJSON.h>
#include <paho_mqtt.h>

#define DBG_ENABLE
#define DBG_SECTION_NAME    "mqtt.sample"
#define DBG_LEVEL           DBG_LOG
#define DBG_COLOR
#include <rtdbg.h>

// MQTT配置 - 请根据实际情况修改
#define MQTT_URI       "tcp://192.168.31.238:1883"
#define MQTT_CLIENT_ID  "stm32f407_client"
#define MQTT_USERNAME   "zterch"    // 如果有认证
#define MQTT_PASSWORD   "zterch"
#define MQTT_SUBTOPIC   "/device/led/control" //订阅的 Topic
#define MQTT_PUBTOPIC   "/mqtt/led_ctr" //推送的 Topic
#define MQTT_WILLMSG    "STM32 device offline!"      //设置断开通知消息

// 主题定义
#define TOPIC_SUBSCRIBE "/device/led/control"
#define TOPIC_PUBLISH   "/device/led/status"

static MQTTClient client;
static int is_started = 0;
static MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;


// LED控制函数
static void led_control(const char *led_color, int status)
{
    if (rt_strcmp(led_color, "red") == 0) {
        rt_pin_write(LED_R, status ? PIN_LOW : PIN_HIGH);
        rt_kprintf("Red LED %s\n", status ? "ON" : "OFF");
    } else if (rt_strcmp(led_color, "blue") == 0) {
        rt_pin_write(LED_B, status ? PIN_LOW : PIN_HIGH);
        rt_kprintf("Blue LED %s\n", status ? "ON" : "OFF");
    } else if (rt_strcmp(led_color, "all") == 0) {
        rt_pin_write(LED_R, status ? PIN_LOW : PIN_HIGH);
        rt_pin_write(LED_B, status ? PIN_LOW : PIN_HIGH);
        rt_kprintf("All LEDs %s\n", status ? "ON" : "OFF");
    }
}

// LED初始化
void led_init(void)
{
    rt_pin_mode(LED_R, PIN_MODE_OUTPUT);
    rt_pin_mode(LED_B, PIN_MODE_OUTPUT);
    rt_pin_write(LED_R, PIN_HIGH);
    rt_pin_write(LED_B, PIN_HIGH);
    rt_kprintf("LED initialized. PE7-Red, PE8-Blue\n");
}

// 发布状态消息
void mqtt_publish_status(const char *status)
{
    if (!is_started) {
        rt_kprintf("MQTT not started, cannot publish\n");
        return;
    }

    char payload[128];
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "device", "stm32f407");
    cJSON_AddStringToObject(root, "status", status);
    cJSON_AddNumberToObject(root, "timestamp", rt_tick_get());

    char *json_str = cJSON_PrintUnformatted(root);
    rt_snprintf(payload, sizeof(payload), "%s", json_str);

    paho_mqtt_publish(&client, QOS1, TOPIC_PUBLISH, payload);
    rt_kprintf("Published: %s\n", payload);

    cJSON_free(json_str);
    cJSON_Delete(root);
}

// 消息处理回调函数 - 处理JSON格式的控制消息
static void mqtt_message_handler(MQTTClient *c, MessageData *msg_data)
{
    char message[256] = {0};
    int len = msg_data->message->payloadlen > 255 ? 255 : msg_data->message->payloadlen;
    memcpy(message, msg_data->message->payload, len);

    rt_kprintf("Received MQTT message: %s\n", message);

    // 解析JSON控制消息
    cJSON *root = cJSON_Parse(message);
    if (root == NULL) {
        rt_kprintf("JSON parse error\n");
        return;
    }

    cJSON *device = cJSON_GetObjectItem(root, "device");
    cJSON *action = cJSON_GetObjectItem(root, "action");

    if (device && action) {
        const char *device_str = cJSON_GetStringValue(device);
        const char *action_str = cJSON_GetStringValue(action);

        rt_kprintf("Control command: device=%s, action=%s\n", device_str, action_str);

        if (rt_strcmp(device_str, "led_red") == 0) {
            if (rt_strcmp(action_str, "on") == 0) {
                led_control("red", 1);
                mqtt_publish_status("led_red_on");
            } else if (rt_strcmp(action_str, "off") == 0) {
                led_control("red", 0);
                mqtt_publish_status("led_red_off");
            }
        } else if (rt_strcmp(device_str, "led_blue") == 0) {
            if (rt_strcmp(action_str, "on") == 0) {
                led_control("blue", 1);
                mqtt_publish_status("led_blue_on");
            } else if (rt_strcmp(action_str, "off") == 0) {
                led_control("blue", 0);
                mqtt_publish_status("led_blue_off");
            }
        }
    } else {
        rt_kprintf("Invalid message format\n");
    }

    cJSON_Delete(root);
}


static void my_mqtt_sub_callback(MQTTClient *c, MessageData *msg_data)
{
    *((char *)msg_data->message->payload + msg_data->message->payloadlen) = '\0';
    LOG_D("mqtt sub callback: %.*s %.*s",
               msg_data->topicName->lenstring.len,
               msg_data->topicName->lenstring.data,
               msg_data->message->payloadlen,
               (char *)msg_data->message->payload);


}

static void my_mqtt_sub_default_callback(MQTTClient *c, MessageData *msg_data)
{
    *((char *)msg_data->message->payload + msg_data->message->payloadlen) = '\0';
    LOG_D("mqtt sub default callback: %.*s %.*s",
               msg_data->topicName->lenstring.len,
               msg_data->topicName->lenstring.data,
               msg_data->message->payloadlen,
               (char *)msg_data->message->payload);
}


//连接回调函数
static void my_mqtt_connect_callback(MQTTClient *c)
{
    LOG_D("MQTT connected callback");
    mqtt_publish_status("online");
}

static void my_mqtt_online_callback(MQTTClient *c)
{
    LOG_D("MQTT online callback");
}

static void my_mqtt_offline_callback(MQTTClient *c)
{
    LOG_D("MQTT offline callback");
}

// MQTT客户端初始化
static int my_mqtt_client_init(void)
{

    if (is_started)
    {
        LOG_E("mqtt client is already connected.");
        return -1;
    }

    {
        client.isconnected = 0;
        client.uri = MQTT_URI;
        rt_memcpy(&client.condata, &connectData, sizeof(connectData));
        client.condata.clientID.cstring = MQTT_CLIENT_ID;
        client.condata.keepAliveInterval = 60;
        client.condata.cleansession = 1;
        client.condata.username.cstring = MQTT_USERNAME; //设置账号
        client.condata.password.cstring = MQTT_PASSWORD; //设置密码

        /* 配置断开通知消息 */
        client.condata.willFlag = 1;
        client.condata.will.qos = 1;
        client.condata.will.retained = 0;
        client.condata.will.topicName.cstring = rt_strdup(TOPIC_PUBLISH);     //设置推送主题,需要分配空间存储 topic，以便后面订阅多个 topic
        client.condata.will.message.cstring = MQTT_WILLMSG;//设置断开通知消息

        /* rt_malloc buffer. 分配缓冲区*/
        client.buf_size = client.readbuf_size = 1024;
        client.buf = rt_calloc(1, client.buf_size);
        client.readbuf = rt_calloc(1, client.readbuf_size);
        if (!(client.buf && client.readbuf))
        {
            LOG_E("no memory for MQTT client buffer!");
            return -1;
        }

        /* 设置事件回调函数，回调函数需要自己编写，在例程中为回调函数留了空函数 */
        client.connect_callback = my_mqtt_connect_callback;       //设置连接回调函数
        client.online_callback = my_mqtt_online_callback;         //设置上线回调函数
        client.offline_callback = my_mqtt_offline_callback;       //设置下线回调函数

        /* 配置订阅表 */
        client.messageHandlers[0].topicFilter = MQTT_SUBTOPIC; //设置第一个订阅的 Topic
        client.messageHandlers[0].callback = mqtt_message_handler;//设置该订阅的回调函数
        client.messageHandlers[0].qos = QOS1;                  //设置该订阅的消息等级
        /* set default subscribe event callback */
        client.defaultMessageHandler = my_mqtt_sub_default_callback; //设置一个默认的回调函数，如果有订阅的 Topic 没有设置回调函数，则使用该默认回调函数

    }

    /* run mqtt client */
    paho_mqtt_start(&client);
    is_started = 1;

    rt_kprintf("MQTT client started, connecting to %s\n", client.uri);
    return 0;
}

// 自动启动MQTT客户端
void auto_start_mqtt(void)
{
    rt_thread_t tid;

    // 创建线程自动启动MQTT
    tid = rt_thread_create("mqtt_auto",
                          (void (*)(void *))my_mqtt_client_init,
                          RT_NULL,
                          2048,
                          RT_THREAD_PRIORITY_MAX / 3,
                          20);
    if (tid != RT_NULL) {
        rt_thread_startup(tid);
    }
}


static int my_mqtt_stop(int argc, char **argv)
{
    if (argc != 1)
    {
        rt_kprintf("mqtt_stop    --stop mqtt worker thread and free mqtt client object.\n");
    }

    is_started = 0;

    return paho_mqtt_stop(&client);
}

static int my_mqtt_publish(int argc, char **argv)
{
    if (is_started == 0)
    {
        LOG_E("mqtt client is not connected.");
        return -1;
    }

    if (argc == 2)
    {
        paho_mqtt_publish(&client, QOS1, MQTT_PUBTOPIC, argv[1]);
    }
    else if (argc == 3)
    {
        paho_mqtt_publish(&client, QOS1, argv[1], argv[2]);
    }
    else
    {
        rt_kprintf("mqtt_publish <topic> [message]  --mqtt publish message to specified topic.\n");
        return -1;
    }

    return 0;
}



static void my_mqtt_new_sub_callback(MQTTClient *client, MessageData *msg_data)
{
    *((char *)msg_data->message->payload + msg_data->message->payloadlen) = '\0';
    LOG_D("mqtt new subscribe callback: %.*s %.*s",
               msg_data->topicName->lenstring.len,
               msg_data->topicName->lenstring.data,
               msg_data->message->payloadlen,
               (char *)msg_data->message->payload);
}

static int my_mqtt_subscribe(int argc, char **argv)
{
    if (argc != 2)
    {
        rt_kprintf("mqtt_subscribe [topic]  --send an mqtt subscribe packet and wait for suback before returning.\n");
        return -1;
    }

    if (is_started == 0)
    {
        LOG_E("mqtt client is not connected.");
        return -1;
    }

    return paho_mqtt_subscribe(&client, QOS1, argv[1], my_mqtt_new_sub_callback);
}

static int my_mqtt_unsubscribe(int argc, char **argv)
{
    if (argc != 2)
    {
        rt_kprintf("mqtt_unsubscribe [topic]  --send an mqtt unsubscribe packet and wait for suback before returning.\n");
        return -1;
    }

    if (is_started == 0)
    {
        LOG_E("mqtt client is not connected.");
        return -1;
    }

    return paho_mqtt_unsubscribe(&client, argv[1]);
}

// MSH命令：手动控制LED
static void cmd_led(int argc, char **argv)
{
    if (argc != 3) {
        rt_kprintf("Usage: led <red|blue|all> <on|off>\n");
        return;
    }

    if (rt_strcmp(argv[2], "on") == 0) {
        led_control(argv[1], 1);

    } else if (rt_strcmp(argv[2], "off") == 0) {
        led_control(argv[1], 0);
    } else {
        rt_kprintf("Unknown command: %s\n", argv[2]);
    }
}
MSH_CMD_EXPORT(cmd_led, Control LED: led <color> <on/off>);

#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT(my_mqtt_client_init, startup mqtt client);
MSH_CMD_EXPORT(my_mqtt_stop, stop mqtt client);
MSH_CMD_EXPORT(my_mqtt_publish, mqtt publish message to specified topic);
MSH_CMD_EXPORT(my_mqtt_subscribe,  mqtt subscribe topic);
MSH_CMD_EXPORT(my_mqtt_unsubscribe, mqtt unsubscribe topic);
#endif /* FINSH_USING_MSH */

// 自动初始化
INIT_APP_EXPORT(auto_start_mqtt);
